---
title: Navigate between pages
description: Learn how to create links to move between pages.
---

import { FileTree } from '~/ui/components/FileTree';

Expo Router uses "links" to move between pages in the app. This is conceptually similar to how the web works with `<a>` tags and the `href` attribute.

<FileTree files={['app/index.tsx', 'app/about.tsx', 'app/user/[id].tsx']} />

In the following example, there are two `<Link />` components which navigate to different routes.

{/* prettier-ignore */}
```tsx app/index.tsx
import { View } from 'react-native';
/* @info Import the <strong>Link</strong> React component from <strong>expo-router</strong> */
import { Link } from 'expo-router';
/* @end */

export default function Page() {
  return (
    <View>
      /* @info Tapping this will link to the <strong>about</strong> page */
      <Link href="/about">About</Link>
      /* @end */
      {/* ...other links */}
      /* @info Tapping this will navigate to the dynamic route <strong>user/[id]</strong> where <strong>id=bacon</strong> */
      <Link href="/user/bacon">View user</Link>
      /* @end */
    </View>
  );
}
```

## Buttons

The Link component wraps the children in a `<Text>` component by default, this is useful for accessibility but not always desired. You can customize the component by passing the `asChild` prop, which will forward all props to the first child of the `Link` component. The child component must support the `onPress` and `onClick` props, `href` and `role` will also be passed down.

{/* prettier-ignore */}
```tsx
import { Pressable, Text } from 'react-native';
import { Link } from 'expo-router';

export default function Page() {
  return (
    /* @info The <strong>onPress</strong> event that navigates to <strong>/other</strong> will be passed to <strong>Pressable</strong> */
    <Link href="/other" asChild>
    /* @end */
      <Pressable>
        <Text>Home</Text>
      </Pressable>
    </Link>
  );
}
```

## Understanding native navigation

Expo Router uses a stack-based navigation approach. Each new route you navigate to gets added to a stack. If you navigate to a route already in the stack, the stack unwinds back to that existing route.

For example, when you navigate from `/feed` to `/profile`, the stack contains `/feed` and `/profile`. If you then navigate to `/settings`, the stack contains `/feed`, `/profile`, and `/settings`. If you then navigate back to `/feed`, the stack unwinds back to `/feed`.

To navigate to a route without the stack unwinding, you can use the `push` prop on the `<Link>` component. This always pushes the route onto the stack, even if it already exists.

In contrast, the `replace` method substitutes the current route in the navigation stack with a new one, effectively replacing the current screen with the new one without adding to the stack.

To navigate, you can provide a full path (`/profile/settings`), a relative path (`../settings`), or by passing an object (`{ pathname: 'profile', params: { id: '123' } }`).

| Name       | Description                                                                                                                                                                                                                                                                                                                               |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `navigate` | Navigate to the nearest route in the navigation state. `navigate` only pushes a new screen if the new route is different (not including search parameters or the hash). Otherwise, the current screen rerenders with the new parameters. If you navigate to a route that is in the history, the stack will dismiss screens to that route. |
| `push`     | Always pushes a new route, and never pops or replaces to existing routes. You can push the current route multiple times or with new parameters.                                                                                                                                                                                           |
| `replace`  | Remove the current route from the history and replace it with the specified URL. This is useful for redirects.                                                                                                                                                                                                                            |

## Relative navigation

> **warning** `relativeToDirectory` will be released in the next version of `expo-router`.

A relative URL is a URL prefix with `./`, such as `./article`, or `./article/`. Relative URLs are resolved relative to the current rendered screen.

The URL of the current screen is a document URL (a URL without a trailing slash), so relative URLs will be resolved relative to the directory. This can be confusing when the current screen is rendered by an `index` file as the relative URL is resolved from the URL's directory, not the file system. By using the `relativeToDirectory` option, Expo Router will instead treat the current URL as a directory URL.

| Href         | Current URL | `relativeToDirectory` | Result              |
| ------------ | ----------- | --------------------- | ------------------- |
| `./article`  | `/route/v1` |                       | `/route/article`    |
| `./article`  | `/route/v1` | `true`                | `/route/v1/article` |
| `../article` | `/route/v1` |                       | `/article`          |
| `../article` | `/route/v1` | `true`                | `/route/article`    |

```ts
// Using `relativeToDirectory` with Link
<Link href="./article" relativeToDirectory>Go to article</Link>

// Using `relativeToDirectory` with the imperative API
router.push("./article", { relativeToDirectory: true })
router.navigate("./article", { relativeToDirectory: true })
router.replace("./article", { relativeToDirectory: true })
```

> **info** Relative URLs without a `./` prefix, such as `article`, are not supported.

## Linking to dynamic routes

Dynamic routes and query parameters can be provided statically or with the convenience **Href** object.

{/* prettier-ignore */}
```tsx app/index.tsx
/* @info Import the <strong>Link</strong> React component from <strong>expo-router</strong> */
import { Link } from 'expo-router';
/* @end */
import { View } from 'react-native';

export default function Page() {
  return (
    <View>
      <Link
        href={{
          /* @info Navigate to <strong>/user/bacon</strong> */
          pathname: '/user/[id]',
          params: { id: 'bacon' }
          /* @end */
        }}>
          View user
        </Link>
    </View>
  );
}
```

## Pushing screens

By default, links `navigate` to the nearest route in the navigation stack, either by pushing a new route or unwinding to an existing route. You can use the `push` prop to always push the route onto the stack.

{/* prettier-ignore */}
```tsx app/index.tsx
import { Link } from 'expo-router';

export default function Page() {
  return (
    <View>
      /* @info Navigate to <strong>/feed</strong> and always add it to the stack. */
      <Link push href="/feed">Login</Link>
      /* @end */
    </View>
  );
}
```

## Replacing screens

By default, links "push" routes onto the navigation stack. It follows the same rules as [`navigation.navigate()`](https://reactnavigation.org/docs/navigating/#navigate-to-a-route-multiple-times). This means that the previous screen will be available when the user navigates back. You can use the `replace` prop to replace the current screen instead of pushing a new one.

{/* prettier-ignore */}
```tsx app/index.tsx
import { Link } from 'expo-router';

export default function Page() {
  return (
    <View>
      /* @info Navigate to <strong>/feed</strong> without adding it to the stack. */
      <Link replace href="/feed">Login</Link>
      /* @end */
    </View>
  );
}
```

Use `router.replace()` to replace the current screen imperatively.

Native navigation does not always support `replace`. For example on X, you wouldn't be able to "replace" directly from a profile to a tweet, this is because the UI requires a back button to return to the feed or other top-level tab screen. In this case, replace would switch to the feed tab, and push the tweet route on top of it, or if you were on a different tweet inside the feed tab, it would replace the current tweet with the new tweet. This exact behavior can be obtained in Expo Router by using [`unstable_settings`](/router/advanced/router-settings).

## Imperative navigation

You can also navigate imperatively using the `router` object. This is useful when you need to perform a navigation action outside a React component, such as in an event handler or a utility function.

```tsx
import { router } from 'expo-router';

export function logout() {
  /* @info Navigate to <strong>/login</strong> */
  router.replace('/login');
  /* @end */
}
```

The `router` object is immutable and contains the following functions:

- **navigate**: `(href: Href) => void`. Perform a `navigate` action.
- **push**: `(href: Href) => void`. Perform a `push` action.
- **replace**: `(href: Href) => void`. Perform a `replace` action.
- **back**: `() => void`. Navigate back to previous route.
- **canGoBack**: `() => boolean` Returns `true` if a valid history stack exists and the `back()` function can pop back.
- **setParams**: `(params: Record<string, string>) => void` Update the query params for the currently selected route.

## Autocomplete

Expo Router can automatically generate static TypeScript types for all routes in your app. This allows you to use autocomplete for `href`s and get warnings when invalid links are used. Learn more: [Statically Typed Routes](/router/reference/typed-routes).

## Web behavior

Expo Router supports the standard `<a>` element when running on web, however this will perform a full-page server-navigation. This is slower and doesn't take full advantage of React. Instead, the Expo Router `<Link>` component will perform client-side navigation, which will preserve the state of the website and navigate faster.

The web-only attributes `target`, `rel`, and `download` are also supported. These will be passed to the `<a>` element when running on web.

Client-side navigation works with both single-page apps, and [static rendering](/router/reference/static-rendering).

## Usage in simulators

See the [testing URLs](/guides/linking#testing-urls) guide to learn how you can emulate deep links in Android Emulators and iOS Simulators.
